<?php

namespace app\common\service\token\driver;

use app\common\service\ServiceBase;
use app\common\service\token\TokenInterface;
use Firebase\JWT\JWT;
use think\facade\Cache;

/**
 * app应用的具体实现，appid+appkey+secret
 * 要求：考虑数据签名，幂等性问题
 */
class AppToken implements TokenInterface
{
    use ServiceBase;

    private $expire = 604800;
    private $refresh_expire = 2419200;

    /**
     * @param $param
     * @return mixed
     */
    public function createAccessToken($param)
    {
        $appkey = $param['appkey'];
        $secret = $param['secret'];

        //生成redis key-value
        $msectime = msectime();
        $access_token_key = strtoupper(md5($appkey . $msectime . $secret));
        $appInfo = $this->cacheAppInfo($appkey, $secret);
        $access_token_val = $this->tokenSign($appInfo);

        //returnData.data
        $data = ['access_token' => $access_token_key, 'appkey' => $appkey, 'expire' => $this->expire];

        //是否需要refresh_token
        if (isset($param['refresh'])) {
            $refresh_token_key = $appkey . '_refresh_token';
            if ($param['refresh'] == true) {
                $refresh_token = strtoupper(md5($access_token_key . '_refresh_token'));
                $data['refresh_token'] = $refresh_token;
                Cache::set($refresh_token_key, $refresh_token, $this->refresh_expire);
            } else {
                Cache::delete($refresh_token_key);
            }

        }

        //cache token
        $old_access_token = $appkey . '_access_token';
        Cache::set($old_access_token, $access_token_key, $this->expire);
        Cache::set($access_token_key, $access_token_val, $this->expire);

        $returnData['data'] = $data;
        return $returnData;
    }

    /**
     * 刷新token时间
     * @param $param
     * @return array
     */
    public function refreshToken($param)
    {
        //get params
        $appkey = $param['appkey'];
        $secret = $param['secret'];
        $accessToken = $param['token'];
        $refresh_token = $param['refresh_token'];
        $refresh_token_key = $appkey . '_refresh_token';
        $encode = Cache::get($refresh_token_key);

        //verify token and refresh token
        if (empty($encode)) ServiceBase::commonError(['code' => 500, 'msg' => 'refresh_token过期', 'success' => false]);
        $refresh_token != $encode && ServiceBase::commonError(['code' => 500, 'msg' => 'refresh_token验证失败', 'success' => false]);
        strtoupper(md5($accessToken . '_refresh_token')) != $refresh_token &&
        ServiceBase::commonError(['code' => 500, 'msg' => 'token验证失败', 'success' => false]);

        //create new token sign
        $appInfo = $this->getAppInfo(['app_key' => $appkey, 'secret' => $secret]);
        $access_token_val = $this->tokenSign($appInfo);

        //overwrite the token value
        Cache::set($appkey . '_access_token', $accessToken, $this->expire);
        Cache::set($accessToken, $access_token_val, $this->expire);

        return ['code' => 200, 'success' => true, 'msg' => '刷新成功'];
    }

    public function checkDataSign($param)
    {

    }

    public function cacheAppInfo($app_key, $secret)
    {
        $app_info_key = $app_key . $secret;
        if (!Cache::has($app_info_key)) {
            $appInfo = $this->getAppInfo(['app_key' => $app_key, 'secret' => $secret]);
            empty($appInfo) && ServiceBase::commonError(['code' => 500, 'msg' => '应用不存在', 'success' => false]);
            Cache::set($app_info_key, json_encode($appInfo), $this->expire);
        } else {
            $appInfo = json_decode(Cache::get($app_info_key), true);
        }
        return $appInfo;
    }

    /**
     * 获取会员信息
     */
    public function getAppInfo($where = [], $field = true)
    {
        return ServiceBase::model('PartnerApp')->getPartnerAppInfo($where, $field);
    }

    /**
     * @param $appinfo
     * @return string
     */
    public function tokenSign($appinfo)
    {
        $key = API_KEY . JWT_KEY;
        $token = [
            'appkey'    => $appinfo['app_key'],
            'secret'    => $appinfo['secret'],
            'expire_at' => TIME_NOW + 7200,
            'create_at' => TIME_NOW
        ];
        return JWT::encode($token, $key);
    }

    public function getAccessTokenInfo($param)
    {
        // TODO: Implement getAccessTokenInfo() method.
    }
}
